package com.orange.core.service.coupon;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orange.core.mapper.coupon.CouponMapper;
import com.orange.core.mapper.shop.ShopMapper;
import com.orange.core.mapper.user.UserMapper;
import com.orange.core.pojo.PageReqDto;
import com.orange.core.pojo.entity.coupon.Coupon;
import com.orange.core.pojo.entity.shop.Shop;
import com.orange.core.pojo.entity.user.User;
import com.orange.core.pojo.enums.EUserType;
import com.orange.core.pojo.req.coupon.CouponPageReq;
import com.orange.core.util.PrincipalUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class CouponService extends ServiceImpl<CouponMapper, Coupon> {

    private final ShopMapper shopMapper;
    private final UserMapper userMapper;

    public Page<Coupon> page(PageReqDto<CouponPageReq> req) {
        if (req.getCondition() == null) {
            req.setCondition(new CouponPageReq());
        }

        CouponPageReq condition = req.getCondition();
        if (PrincipalUtil.isUser()) {
            if (Objects.equals(condition.getSource(), 2)) {
                User user = userMapper.selectById(PrincipalUtil.getId());
                if (Objects.equals(user.getType(), EUserType.MERCHANT.getValue())) {
                    condition.setShopId(user.getShopId());
                }
            }
        }

        Page<Coupon> page = this.lambdaQuery()
                .eq(condition.getCategoryId() != null, Coupon::getCategoryId, condition.getCategoryId())
                .eq(condition.getShopId() != null, Coupon::getShopId, condition.getShopId())
                .eq(condition.getShelf() != null, Coupon::getShelf, condition.getShelf())
                .orderByDesc(Coupon::getId)
                .page(req.toPage());
        List<Coupon> coupons = page.getRecords();
        if (CollUtil.isNotEmpty(coupons)) {
            List<Integer> shopIds = coupons.stream().map(Coupon::getShopId).toList();
            Map<Integer, Shop> shopMap = shopMapper.selectBatchIds(shopIds)
                    .stream().collect(Collectors.toMap(Shop::getId, Function.identity()));
            for (Coupon coupon : coupons) {
                Shop shop = shopMap.get(coupon.getShopId());
                coupon.setShopName(shop.getName());
                coupon.setShopAddress(shop.getAddress());
                coupon.setShopIconUrl(shop.getLogo());
                coupon.setBanners(shop.getImageUrl());
            }
        }
        return page;
    }

    @Transactional
    public boolean shelf(int id, int shelf) {
        Coupon coupon = this.getById(id);
        Assert.notNull(coupon, "无此优惠券");
        if (shelf == 1) {
            Assert.isTrue(coupon.getStock() > 0, "库存不足，请先补充库存");
        }
        Assert.isTrue(!coupon.getEffectEnd().isBefore(LocalDate.now()), "优惠券已过期，无法上架");

        return this.lambdaUpdate()
                .set(Coupon::getShelf, shelf)
                .eq(Coupon::getId, id)
                .update();
    }

    @Transactional
    public boolean changeStock(int id, int stock) {
        if (stock == 0) {
            shelf(id, 0);
        }
        return this.lambdaUpdate()
                .set(Coupon::getStock, stock)
                .eq(Coupon::getId, id)
                .update();
    }

    @Transactional
    public void deductStock(int id, int stock) {
        Assert.isTrue(stock > 0, "库存扣减数量应大于0");
        Assert.isTrue(baseMapper.deductStock(id, stock), "库存不足");

        // 检查库存数量
        Coupon coupon = this.lambdaQuery()
                .eq(Coupon::getId, id)
                .one();
        if (Objects.equals(coupon.getStock(), 0)) {
            shelf(id, 0);
        }
    }

    @Transactional
    public void addStock(int id, int stock) {
        Assert.isTrue(stock > 0, "库存增加数量应大于0");
        this.lambdaUpdate()
                .setSql("stock = stock + " + stock)
                .eq(Coupon::getId, id)
                .update();
    }
}
